package cloud.xuxiaowei.file.config;

import cloud.xuxiaowei.core.properties.SecurityProperties;
import cloud.xuxiaowei.core.utils.SecurityUtils;
import cloud.xuxiaowei.oauth2.config.CsrfTokenRepositoryConfig;
import cloud.xuxiaowei.oauth2.handler.ResourceAccessDeniedHandler;
import cloud.xuxiaowei.oauth2.matcher.AuthorizePermitAllRequestMatcher;
import cloud.xuxiaowei.oauth2.matcher.CsrfIgnoreRequestMatcher;
import cloud.xuxiaowei.oauth2.point.ResourceServerAuthenticationEntryPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.csrf.CsrfTokenRepository;

import java.security.interfaces.RSAPublicKey;
import java.util.List;

/**
 * @author xuxiaowei
 * @since 0.0.1
 */
@Configuration
public class ResourceServerConfig {

	private SecurityProperties securityProperties;

	/**
	 * @see CsrfTokenRepositoryConfig#csrfTokenRepository()
	 */
	private CsrfTokenRepository csrfTokenRepository;

	private AuthorizePermitAllRequestMatcher[] authorizePermitAllRequestMatchers = new AuthorizePermitAllRequestMatcher[0];

	private CsrfIgnoreRequestMatcher[] csrfIgnoreRequestMatchers = new CsrfIgnoreRequestMatcher[0];

	@Autowired
	public void setSecurityProperties(SecurityProperties securityProperties) {
		this.securityProperties = securityProperties;
	}

	@Autowired
	public void setCsrfTokenRepository(CsrfTokenRepository csrfTokenRepository) {
		this.csrfTokenRepository = csrfTokenRepository;
	}

	@Autowired(required = false)
	public void setAuthorizePermitAllRequestMatchers(
			AuthorizePermitAllRequestMatcher[] authorizePermitAllRequestMatchers) {
		this.authorizePermitAllRequestMatchers = authorizePermitAllRequestMatchers;
	}

	@Autowired(required = false)
	public void setCsrfIgnoreRequestMatchers(CsrfIgnoreRequestMatcher[] csrfIgnoreRequestMatchers) {
		this.csrfIgnoreRequestMatchers = csrfIgnoreRequestMatchers;
	}

	@Bean
	public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {

		List<SecurityProperties.RequestMatcher> requestMatchers = securityProperties.getRequestMatchers();

		http.authorizeRequests(customizer -> {

			customizer.requestMatchers(authorizePermitAllRequestMatchers);

			SecurityUtils.authorizeRequests(requestMatchers, customizer);

			// 其他地址：需要授权访问，此配置要放在最后一行
			customizer.anyRequest().authenticated();

		});

		http.oauth2ResourceServer(customizer -> {
			customizer.jwt(jwtCustomizer -> {
				RSAPublicKey rsaPublicKey = securityProperties.rsaPublicKey();
				NimbusJwtDecoder.PublicKeyJwtDecoderBuilder publicKeyJwtDecoderBuilder = NimbusJwtDecoder
					.withPublicKey(rsaPublicKey);
				NimbusJwtDecoder nimbusJwtDecoder = publicKeyJwtDecoderBuilder.build();
				jwtCustomizer.decoder(nimbusJwtDecoder);
			});
		});

		http.oauth2ResourceServer(customizer -> customizer
			// 资源服务 身份验证入口点
			.authenticationEntryPoint(new ResourceServerAuthenticationEntryPoint())
			// 资源访问拒绝 处理程序
			.accessDeniedHandler(new ResourceAccessDeniedHandler()));

		http.csrf(customizer -> customizer
			// 基于 RequestMatcher Bean 的配置
			.ignoringRequestMatchers(csrfIgnoreRequestMatchers)
			// 基于 URL 的配置
			.ignoringAntMatchers(securityProperties.getCsrfIgnores())
			// CSRF 配置
			.csrfTokenRepository(csrfTokenRepository));

		return http.build();
	}

}
